package com.example.questionsystem.modules.qu.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Arrays;
import java.util.Base64;

public class AESDecryptor {

    static {
        // 注册BouncyCastle安全提供者
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 解密文件内容
     * @param file 文件
     * @param key 密钥
     * @param iv 初始向量
     * @return 解密后的内容
     * @throws Exception 如果解密过程中出现错误
     */
    public static String decryptFile(MultipartFile file, String key, String iv) throws Exception {
        byte[] encryptedBytes = file.getBytes();
        String encryptedBase64 = new String(encryptedBytes, StandardCharsets.UTF_8);
        return decrypt(encryptedBase64, key, iv);
    }

    /**
     * 处理密钥或初始向量，不足 16 位时后面补 0
     * @param input 输入的密钥或初始向量字符串
     * @return 处理后的字节数组
     */
    private static byte[] padTo16Bytes(String input) {
        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
        // 创建一个长度为 16 的新数组
        byte[] result = new byte[16];
        // 将原数组内容复制到新数组
        System.arraycopy(inputBytes, 0, result, 0, Math.min(inputBytes.length, 16));
        // 如果原数组长度小于 16，后面补 0
        if (inputBytes.length < 16) {
            for (int i = inputBytes.length; i < 16; i++) {
                result[i] = 0;
            }
        }
        return result;
    }
    /**
     * 加密文本内容
     * @param plainText 待加密的原始文本
     * @param keyStr 密钥字符串
     * @param ivStr 初始化向量字符串
     * @return Base64编码的加密字符串
     * @throws Exception 加密过程中的异常
     */
    public static String encrypt(String plainText, String keyStr, String ivStr) throws Exception {
        byte[] keyBytes = padTo16Bytes(keyStr);
        byte[] ivBytes = padTo16Bytes(ivStr);

        // 初始化AES加密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

        // 执行加密
        byte[] encryptedData = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        // Base64编码
        return Base64.getEncoder().encodeToString(encryptedData);
    }
    /**
     * 使用AES PCK7填充模式加密数据
     * @param data 待加密数据
     * @param key 加密密钥（16字节）
     * @return 加密后的数据
     */
    public static String encryptAESImage(byte[] data, String key, String ivStr) throws Exception {

        byte[] keyBytes = padTo16Bytes(key);
        byte[] ivBytes = padTo16Bytes(ivStr);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] bytes = cipher.doFinal(data);
        return Base64.getEncoder().encodeToString(bytes);
    }
    /**
     * 解密使用AES PCK7填充模式加密并Base64编码的图片数据
     * @param encryptedBase64 加密并Base64编码后的字符串
     * @param key 解密密钥（16字节）
     * @param ivStr 初始化向量字符串
     * @return 解密后的原始图片字节数组
     * @throws Exception 解密过程中的异常
     */
    public static byte[] decryptAESImage(String encryptedBase64, String key, String ivStr) throws Exception {
        // 清理并补全 Base64 字符串
        encryptedBase64 = cleanAndPadBase64(encryptedBase64);
        // Base64解码
        byte[] encryptedData = Base64.getDecoder().decode(encryptedBase64);

        byte[] keyBytes = padTo16Bytes(key);
        byte[] ivBytes = padTo16Bytes(ivStr);

        // 初始化AES解密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

        // 执行解密
        byte[] bytes = cipher.doFinal(encryptedData);
        return bytes;
    }
    /**
     * 解密Base64编码的加密内容
     * @param encryptedContent Base64编码的加密字符串
     * @param keyStr 密钥字符串
     * @param ivStr 初始化向量字符串
     * @return 解密后的原始字符串
     * @throws Exception 解密过程中的异常
     */
    public static String decrypt(String encryptedContent, String keyStr, String ivStr) throws Exception {

        // Base64解码
       byte[] encryptedData = Base64.getDecoder().decode(encryptedContent);

        byte[] keyBytes = processKey(keyStr);

        byte[] ivBytes = processIV(ivStr);

        // 初始化AES加密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        
        // 执行解密
        byte[] decryptedData = cipher.doFinal(encryptedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }
    /**
     * 清理非法字符并补全 Base64 字符串
     * @param base64Str 原始 Base64 字符串
     * @return 清理并补全后的 Base64 字符串
     */
    private static String cleanAndPadBase64(String base64Str) {
        // 清理非法字符
        String cleanContent = base64Str.replaceAll("[^A-Za-z0-9+/=]", "");
        // 计算需要补充的填充字符数量
        int paddingNeeded = (4 - (cleanContent.length() % 4)) % 4;
        // 补充填充字符
        StringBuilder paddedContent = new StringBuilder(cleanContent);
        for (int i = 0; i < paddingNeeded; i++) {
            paddedContent.append('=');
        }
        return paddedContent.toString();
    }
    public static byte[]  decryptBase(byte [] encryptedContent, String keyStr, String ivStr) throws Exception {
        // 先将字节数组转换为字符串
        String encryptedBase64 = new String(encryptedContent, StandardCharsets.UTF_8);
        // 清理并补全 Base64 字符串
        encryptedBase64 = cleanAndPadBase64(encryptedBase64);
        // Base64解码
        byte[] encryptedData = Base64.getDecoder().decode(encryptedBase64);

        byte[] keyBytes = processKey(keyStr);

        byte[] ivBytes = processIV(ivStr);

        // 初始化AES加密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

        // 执行解密

        return cipher.doFinal(encryptedData);
    }

    private static byte[] processKey(String key) throws Exception {
        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
        int keyLength = keyBytes.length;
        
        if (keyLength < 16) {
            // 计算MD5值
            String md5 = getMD5(key).toLowerCase();;
            byte[] md5Bytes = md5.getBytes(StandardCharsets.UTF_8);
            

            
            // 创建新数组：原始key + MD5值的前paddingLength个字节
            byte[] newKey = new byte[16];
            System.arraycopy(md5Bytes, 0, newKey, 0, 16);

            
            return  newKey;
        }
        return keyBytes;
    }

    private static byte[] processIV(String iv) throws Exception {
        byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
        int ivLength = ivBytes.length;
        
        if (ivLength < 16) {
            // 计算MD5值
            String md5 = getMD5(iv).toLowerCase();
            byte[] md5Bytes = md5.getBytes(StandardCharsets.UTF_8);
            int md5Length = md5Bytes.length;
            
            // 计算需要填充的字节数
            int paddingLength = 16 - ivLength;
            
            // 创建新数组：原始iv + MD5值的后paddingLength个字节
            byte[] newIV = new byte[16];
            System.arraycopy(md5Bytes, 16, newIV, 0, 16);
            
            return newIV;
        }
        return ivBytes;
    }

    private static String getMD5(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }

    /**
     * 读取文件内容，进行Base64解码，然后解密，最后再进行Base64解码
     * @param filePath 文件路径
     * @param key 密钥
     * @param iv 初始向量
     * @return 最终解码后的字节数组
     */
    public static String readAndDecryptFile(String filePath, String key, String iv) throws Exception {
        // 读取文件内容
        byte[] fileContent = Files.readAllBytes(Paths.get(filePath));
        String s = new String(fileContent, StandardCharsets.UTF_8);
        String decrypt = decrypt(s, key, iv);
        byte[] bytes = decryptBase(decrypt.getBytes(StandardCharsets.UTF_8), key, iv);

        return new String(bytes, StandardCharsets.UTF_8);
    }
    // 测试用例
    public static void main(String[] args) throws Exception {


        String filePath = "C:\\Users\\Administrator\\Desktop\\library.libr";
        byte[] fileContent = Files.readAllBytes(Paths.get(filePath));
        String key = "import0000000000";
        String iv = "0000000000000000";
        String s = new String(fileContent, StandardCharsets.UTF_8);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        // 执行解密
        byte[] decryptedData = cipher.doFinal(s.getBytes(StandardCharsets.UTF_8));
        String string = new String(decryptedData, StandardCharsets.UTF_8);
        System.out.println(string);

//


    }
}